﻿﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using System.Threading;

namespace XMouse360
{
	class XControl
	{
		#region events
		public event EventHandler LeftStick;
		public event EventHandler RightStick;
		public event EventHandler XDown;
		public event EventHandler XUp;
		public event EventHandler YDown;
		public event EventHandler YUp;
		public event EventHandler ADown;
		public event EventHandler AUp;
		public event EventHandler BDown;
		public event EventHandler BUp;
		public event EventHandler LShoulderDown;
		public event EventHandler LShoulderUp;
		public event EventHandler RShoulderDown;
		public event EventHandler RShoulderUp;
		public event EventHandler RightTrigger;
		public event EventHandler LeftTrigger;
		public event EventHandler DPadDownPressed;
		public event EventHandler DPadDownUnpressed;
		public event EventHandler DPadUpPressed;
		public event EventHandler DPadUpUnpressed;
		public event EventHandler DPadLeftPressed;
		public event EventHandler DPadLeftUnpressed;
		public event EventHandler DPadRightPressed;
		public event EventHandler DPadRightUnpressed;
		public event EventHandler BackDown;
		public event EventHandler BackUp;
		public event EventHandler StartDown;
		public event EventHandler StartUp;
		public event EventHandler PluggedIn;
		public event EventHandler Unplugged;
		public event EventHandler RightStickDown;
		public event EventHandler RightStickUp;
		public event EventHandler LeftStickDown;
		public event EventHandler LeftStickUp;
		#endregion

		#region private vars
		private ushort updatePeriod;
		private GamePadState Controller;
		private PlayerIndex Index;
		private Vector2 leftStick;
		private Vector2 rightStick;
		private float leftTrigger;
		private float rightTrigger;
		private DPadButtons DPad;
		private Thread ControllerThread;
		//private GamePadButtons buttons;
		private bool[] buttons = new bool[10];
		private static readonly int A = 0;
		private static readonly int B = 1;
		private static readonly int X = 2;
		private static readonly int Y = 3;
		private static readonly int LSTICK = 4;
		private static readonly int RSTICK = 5;
		private static readonly int LSHOULD = 6;
		private static readonly int RSHOULD = 7;
		private static readonly int BACK = 8;
		private static readonly int START = 9;
		private bool isConnected;
		#endregion


		public XControl()
		{
			Index = PlayerIndex.One;
			Controller = GamePad.GetState(Index);
			isConnected = Controller.IsConnected;
			ControllerThread = new Thread(run);
			UpdateButtons();
			DPad = DPadState;
		}

		public XControl(int playerIndex)
		{
			switch (playerIndex)
			{
				case 1: Index = PlayerIndex.One; break;
				case 2: Index = PlayerIndex.Two; break;
				case 3: Index = PlayerIndex.Three; break;
				case 4: Index = PlayerIndex.Four; break;
				default: throw new IndexOutOfRangeException("Invalid Player Index");
			}
			Controller = GamePad.GetState(Index);
			isConnected = Controller.IsConnected;
			ControllerThread = new Thread(run);
			UpdateButtons();
			DPad = DPadState;
		}

		public bool IsPluggedIn
		{
			get { return Controller.IsConnected; }
		}

		public float RTriggerState
		{
			get { return rightTrigger; }
		}

		public float LTriggerState
		{
			get { return leftTrigger; }
		}

		public Vector2 LStickState
		{
			get { return new Vector2(leftStick.X, leftStick.Y); }
		}

		public Vector2 RStickState
		{
			get { return new Vector2(rightStick.X, rightStick.Y); }
		}

		public GamePadButtons ButtonsState
		{
			get { return Controller.Buttons; }
		}

﻿  ﻿  public ushort UpdatePeriod
﻿  ﻿  {
﻿  ﻿  ﻿  get { return updatePeriod; }
﻿  ﻿  ﻿  set { updatePeriod = value; }
﻿  ﻿  }



	  public DPadButtons DPadState
	  {
﻿  ﻿  ﻿  get { return new DPadButtons(Controller); }
	  }

	  public class DPadButtons
	  {
		  public byte DPadFlags;
		  public static readonly byte UP = (byte)0x01;
		  public static readonly byte DOWN = (byte)0x02;
		  public static readonly byte LEFT = (byte)0x04;
		  public static readonly byte RIGHT = (byte)0x08;

		  public DPadButtons(GamePadState Controller)
		  {
			  DPadFlags = 0;
			  DPadFlags += (byte)(Controller.DPad.Up == ButtonState.Pressed ? UP : 0);
			  DPadFlags += (byte)(Controller.DPad.Down == ButtonState.Pressed ? DOWN : 0);
			  DPadFlags += (byte)(Controller.DPad.Left == ButtonState.Pressed ? LEFT : 0);
			  DPadFlags += (byte)(Controller.DPad.Right == ButtonState.Pressed ? RIGHT : 0);
		  }

		  public bool Up()
		  {
			  return ((DPadFlags & (byte)0x01) > 0);
		  }

		  public bool Down()
		  {
			  return ((DPadFlags & (byte)0x02) > 0);
		  }

		  public bool Left()
		  {
			  return ((DPadFlags & (byte)0x04) > 0);
		  }

		  public bool Right()
		  {
			  return ((DPadFlags & (byte)0x08) > 0);
		  }
	  }





	  public GamePadState GetState()
	  {
		  return GamePad.GetState(Index);
	  }




	  public void StartController()
	  {
		  ControllerThread.Start();
	  }

	  public void StopController()
	  {
		  if (ControllerThread.ThreadState == ThreadState.Running)
		  {
			  ControllerThread.Abort();
		  }
	  }

	  private void runloop()
	  {
		  Controller = GamePad.GetState(Index);

		  if (isConnected != Controller.IsConnected)
		  {
			  if (!isConnected)
			  {
				  PluggedIn.Invoke(Controller, EventArgs.Empty);
			  }
			  else
			  {
				  Unplugged.Invoke(Controller, EventArgs.Empty);
			  }
		  }

		  #region thumbsticks
		  if (!Controller.ThumbSticks.Left.Equals(LStickState) ||
			  Controller.ThumbSticks.Left.Length() != 0f)
		  {
			  LeftStick.Invoke(Controller.ThumbSticks.Left, EventArgs.Empty);
			  leftStick = Controller.ThumbSticks.Left;
			  leftStick = LStickState;
		  }

		  if (Controller.ThumbSticks.Right.Length() != 0 ||
			  !Controller.ThumbSticks.Right.Equals(RStickState))
		  {
			  RightStick.Invoke(Controller.ThumbSticks.Right, EventArgs.Empty);
			  rightStick = Controller.ThumbSticks.Right;
			  rightStick = RStickState;
		  }
		  #endregion

		  #region booleanbuttons
		  if (buttons[A] != Controller.IsButtonDown(Buttons.A))
		  {
			  if (!buttons[A])
			  {
				  ADown.Invoke(Controller.Buttons.A, EventArgs.Empty);
			  }
			  else
			  {
				  AUp.Invoke(Controller.Buttons.A, EventArgs.Empty);
			  }
		  }
		  if (buttons[B] != Controller.IsButtonDown(Buttons.B))
		  {
			  if (!buttons[B])
			  {
				  BDown.Invoke(Controller.Buttons.B, EventArgs.Empty);
			  }
			  else
			  {
				  BUp.Invoke(Controller.Buttons.B, EventArgs.Empty);
			  }
		  }
		  if (buttons[X] != Controller.IsButtonDown(Buttons.X))
		  {
			  if (!buttons[X])
			  {
				  XDown.Invoke(Controller.Buttons.X, EventArgs.Empty);
			  }
			  else
			  {
				  XUp.Invoke(Controller.Buttons.X, EventArgs.Empty);
			  }
		  }
		  if (buttons[Y] != Controller.IsButtonDown(Buttons.Y))
		  {
			  if (!buttons[Y])
			  {
				  YDown.Invoke(Controller.Buttons.Y, EventArgs.Empty);
			  }
			  else
			  {
				  YUp.Invoke(Controller.Buttons.Y, EventArgs.Empty);
			  }
		  }
		  if (buttons[LSTICK] != Controller.IsButtonDown(Buttons.LeftStick))
		  {
			  if (!buttons[LSTICK])
			  {
				  LeftStickDown.Invoke(Controller.Buttons.LeftStick, EventArgs.Empty);
			  }
			  else
			  {
				  LeftStickUp.Invoke(Controller.Buttons.LeftStick, EventArgs.Empty);
			  }
		  }
		  if (buttons[RSTICK] != Controller.IsButtonDown(Buttons.RightStick))
		  {
			  if (!buttons[RSTICK])
			  {
				  RightStickDown.Invoke(Controller.Buttons.RightStick, EventArgs.Empty);
			  }
			  else
			  {
				  RightStickUp.Invoke(Controller.Buttons.RightStick, EventArgs.Empty);
			  }
		  }
		  if (buttons[LSHOULD] != Controller.IsButtonDown(Buttons.LeftShoulder))
		  {
			  if (!buttons[LSHOULD])
			  {
				  LShoulderDown.Invoke(Controller.Buttons.LeftShoulder, EventArgs.Empty);
			  }
			  else
			  {
				  LShoulderUp.Invoke(Controller.Buttons.A, EventArgs.Empty);
			  }
		  }
		  if (buttons[RSHOULD] != Controller.IsButtonDown(Buttons.RightShoulder))
		  {
			  if (!buttons[RSHOULD])
			  {
				  RShoulderDown.Invoke(Controller.Buttons.RightShoulder, EventArgs.Empty);
			  }
			  else
			  {
				  RShoulderUp.Invoke(Controller.Buttons.RightShoulder, EventArgs.Empty);
			  }
		  }
		  if (buttons[BACK] != Controller.IsButtonDown(Buttons.Back))
		  {
			  if (!buttons[BACK])
			  {
				  BackDown.Invoke(Controller.Buttons.Back, EventArgs.Empty);
			  }
			  else
			  {
				  BackUp.Invoke(Controller.Buttons.Back, EventArgs.Empty);
			  }
		  }
		  if (buttons[START] != Controller.IsButtonDown(Buttons.Start))
		  {
			  if (!buttons[START])
			  {
				  StartDown.Invoke(Controller.Buttons.Start, EventArgs.Empty);
			  }
			  else
			  {
				  StartUp.Invoke(Controller.Buttons.Start, EventArgs.Empty);
			  }
		  }
		  UpdateButtons();
		  #endregion

		  #region triggers
		  if (Controller.Triggers.Left != 0 || Controller.Triggers.Left != leftTrigger)
		  {
			  LeftTrigger(Controller.Triggers.Left, EventArgs.Empty);
			  leftTrigger = Controller.Triggers.Left;
		  }

		  if (Controller.Triggers.Right != 0 || Controller.Triggers.Right != rightTrigger)
		  {
			  RightTrigger(Controller.Triggers.Right, EventArgs.Empty);
			  rightTrigger = Controller.Triggers.Right;
		  }
		  #endregion

		  #region DPad
		  if (Controller.IsButtonDown(Buttons.DPadDown) != DPad.Down())
		  {
			  if (!DPad.Down())
			  {
				  DPadDownPressed.Invoke(Controller.DPad.Down, EventArgs.Empty);
				  DPad.DPadFlags &= (byte)(0xFF - DPadButtons.DOWN);
			  }
			  else
			  {
				  DPadDownUnpressed.Invoke(Controller.DPad.Down, EventArgs.Empty);
				  DPad.DPadFlags |= DPadButtons.DOWN;
			  }
		  }

		  if (Controller.IsButtonDown(Buttons.DPadUp) != DPad.Up())
		  {
			  if (!DPad.Up())
			  {
				  DPadUpPressed.Invoke(Controller.DPad.Up, EventArgs.Empty);
				  DPad.DPadFlags &= (byte)(0xFF - DPadButtons.UP);
			  }
			  else
			  {
				  DPadUpUnpressed.Invoke(Controller.DPad.Up, EventArgs.Empty);
				  DPad.DPadFlags |= DPadButtons.UP;
			  }
		  }

		  if (Controller.IsButtonDown(Buttons.DPadLeft) != DPad.Left())
		  {
			  if (!DPad.Left())
			  {
				  DPadLeftPressed.Invoke(Controller.DPad.Left, EventArgs.Empty);
				  DPad.DPadFlags &= (byte)(0xFF - DPadButtons.LEFT);
			  }
			  else
			  {
				  DPadLeftUnpressed.Invoke(Controller.DPad.Left, EventArgs.Empty);
				  DPad.DPadFlags |= DPadButtons.LEFT;
			  }
		  }

		  if (Controller.IsButtonDown(Buttons.DPadRight) != DPad.Right())
		  {
			  if (!DPad.Right())
			  {
				  DPadRightPressed.Invoke(Controller.DPad.Right, EventArgs.Empty);
				  DPad.DPadFlags &= (byte)(0xFF - DPadButtons.RIGHT);
			  }
			  else
			  {
				  DPadRightUnpressed.Invoke(Controller.DPad.Right, EventArgs.Empty);
				  DPad.DPadFlags |= DPadButtons.RIGHT;
			  }
		  }

		  #endregion

		  Thread.Sleep(updatePeriod);

	  }

	  private void run()
	  {
		  try
		  {
			  while (true)
			  {
				  runloop();
			  }
		  }
		  catch (ThreadAbortException e)
		  {
			  e.ToString();
			  return;
		  }
	  }

	  private void UpdateButtons()
	  {
		  buttons[RSTICK] = (Controller.Buttons.RightStick == ButtonState.Pressed);
		  buttons[LSTICK] = (Controller.Buttons.LeftStick == ButtonState.Pressed);
		  buttons[RSHOULD] = (Controller.Buttons.RightShoulder == ButtonState.Pressed);
		  buttons[LSHOULD] = (Controller.Buttons.LeftShoulder == ButtonState.Pressed);
		  buttons[A] = (Controller.Buttons.A == ButtonState.Pressed);
		  buttons[B] = (Controller.Buttons.B == ButtonState.Pressed);
		  buttons[X] = (Controller.Buttons.X == ButtonState.Pressed);
		  buttons[Y] = (Controller.Buttons.Y == ButtonState.Pressed);
		  buttons[BACK] = (Controller.Buttons.Back == ButtonState.Pressed);
		  buttons[START] = (Controller.Buttons.Start == ButtonState.Pressed);
	  }

	}
}
